/**
 * @file usr_hrpwm_handle.c
 * @author 黑马小乌龟 (532352406@qq.com)
 * @brief 
 * @version 0.1
 * @date 2025-07-13
 * 
 * @copyright Copyright (c) 2025
 * 
 */
#include "usr_cfg.h"
#include "usr_hrpwm_handle.h"
#include <hc32_ll_hrpwm.h>
#include <hc32f334.h>

/**
 * @brief  Configure PWM dead time function
 * @param  None
 * @retval None
 */
static void DeadTime_Config(CM_HRPWM_TypeDef *hrpwm_handle) {
    stc_hrpwm_deadtime_config_t stcDeadTimeConfig;
    (void)HRPWM_DeadTimeStructInit(&stcDeadTimeConfig);
    /* Set dead time value */
    HRPWM_SetDeadTimeUpValue(hrpwm_handle, HRPWM_DEADTIME_VALUE);
    HRPWM_SetDeadTimeDownValue(hrpwm_handle, HRPWM_DEADTIME_VALUE);

    /* DeadTime function configure */
    stcDeadTimeConfig.u32EqualUpDown = HRPWM_DEADTIME_EQUAL_OFF;
    stcDeadTimeConfig.u32BufUp = HRPWM_DEADTIME_CNT_UP_BUF_OFF;
    stcDeadTimeConfig.u32BufDown = HRPWM_DEADTIME_CNT_DOWN_BUF_OFF;
    (void)HRPWM_DeadTimeConfig(hrpwm_handle, &stcDeadTimeConfig);
}
/**
 * @brief  HRPWM count peak and valley interrupt handler.
 * @param  None
 * @retval None
 */
void HRPWM_1_Ovf_Udf_Handler(void)
{
    // static uint8_t i = 0U;

    // /* Set General Compare Register buffer Value */
    // if (0U == i) {
    //     HRPWM_SetCompareAValue_Buf(HRPWM_PWM_UNIT, HRPWM_CMP_BUF_VALUE);
    //     HRPWM_SetCompareBValue_Buf(HRPWM_PWM_UNIT, HRPWM_CMP_BUF_VALUE);
    //     i = 1U;
    // } else {
    //     HRPWM_SetCompareAValue_Buf(HRPWM_PWM_UNIT, HRPWM_CMP_VALUE);
    //     HRPWM_SetCompareBValue_Buf(HRPWM_PWM_UNIT, HRPWM_CMP_VALUE);
    //     i = 0U;
    // }
}

/**
 * @brief  Configure PWM output
 * @param  [in] HRPWMx               HRPWM unit
 *  @arg CM_HRPWM_x
 * @retval None
 */
static void PWM_Config_Buck(CM_HRPWM_TypeDef *HRPWMx)
{
    stc_hrpwm_init_t stcHrpwmInit;
    stc_hrpwm_pwm_init_t stcPwmInit;

    (void)HRPWM_StructInit(&stcHrpwmInit);
    #if 0
    /* HRPWM general count function configure */
    stcHrpwmInit.u32CountMode = HRPWM_MD_TRIANGLE;
    stcHrpwmInit.u32CountReload = HRPWM_CNT_RELOAD_ON;
    stcHrpwmInit.u32PeriodValue = HRPWM_PERIOD_VALUE;
    (void)HRPWM_Init(HRPWMx, &stcHrpwmInit);

    (void)HRPWM_PWM_StructInit(&stcPwmInit);
    /* Configure PWM output */
    stcPwmInit.u32CompareValue = HRPWM_CMP_VALUE;
    stcPwmInit.u32StartPolarity = A_start_level;
    stcPwmInit.u32UpMatchAPolarity = HRPWM_PWM_UP_MATCH_A_INVT;
    stcPwmInit.u32PeakPolarity = HRPWM_PWM_PEAK_HOLD;
    stcPwmInit.u32DownMatchAPolarity = HRPWM_PWM_DOWN_MATCH_A_INVT;
    stcPwmInit.u32ValleyPolarity = HRPWM_PWM_VALLEY_HOLD;
    #else
    /* HRPWM general count function configure */
    stcHrpwmInit.u32CountMode = HRPWM_MD_SAWTOOTH;
    stcHrpwmInit.u32CountReload = HRPWM_CNT_RELOAD_ON;
    stcHrpwmInit.u32PeriodValue = HRPWM_PERIOD_VALUE;
    (void)HRPWM_Init(HRPWMx, &stcHrpwmInit);

    (void)HRPWM_PWM_StructInit(&stcPwmInit);
    /* Configure PWM output */
    stcPwmInit.u32CompareValue = BUCK_HRPWM_CMP_MINI_DUTY_VALUE;
    stcPwmInit.u32StartPolarity = HRPWM_PWM_START_LOW;
    stcPwmInit.u32UpMatchAPolarity = HRPWM_PWM_UP_MATCH_A_HIGH;
    stcPwmInit.u32PeakPolarity = HRPWM_PWM_PEAK_HOLD;
    stcPwmInit.u32DownMatchAPolarity = HRPWM_PWM_DOWN_MATCH_A_HOLD;
    stcPwmInit.u32ValleyPolarity = HRPWM_PWM_VALLEY_HOLD;
    #endif
    
    stcPwmInit.u32UpMatchBPolarity = HRPWM_PWM_UP_MATCH_B_LOW;
    stcPwmInit.u32DownMatchBPolarity = HRPWM_PWM_DOWN_MATCH_B_HOLD;
    stcPwmInit.u32UpMatchEPolarity = HRPWM_PWM_UP_MATCH_E_HOLD;
    stcPwmInit.u32DownMatchEPolarity = HRPWM_PWM_DOWN_MATCH_E_HOLD;
    stcPwmInit.u32UpMatchFPolarity = HRPWM_PWM_UP_MATCH_F_HOLD;
    stcPwmInit.u32DownMatchFPolarity = HRPWM_PWM_DOWN_MATCH_F_HOLD;
    stcPwmInit.u32UpMatchSpecialAPolarity = HRPWM_PWM_UP_MATCH_SPECIAL_A_HOLD;
    stcPwmInit.u32DownMatchSpecialAPolarity = HRPWM_PWM_DOWN_MATCH_SPECIAL_A_HOLD;
    stcPwmInit.u32UpMatchSpecialBPolarity = HRPWM_PWM_UP_MATCH_SPECIAL_B_HOLD;
    stcPwmInit.u32DownMatchSpecialBPolarity = HRPWM_PWM_DOWN_MATCH_SPECIAL_B_HOLD;
    (void)HRPWM_PWM_ChAInit(HRPWMx, &stcPwmInit);
    stcPwmInit.u32StartPolarity = HRPWM_PWM_START_HIGH;
    (void)HRPWM_PWM_ChBInit(HRPWMx, &stcPwmInit);
    /* PWM output enable */
    HRPWM_PWM_ChAOutputEnable(HRPWMx);
    HRPWM_PWM_ChBOutputEnable(HRPWMx);
}

/**
 * @brief  Configure PWM output
 * @param  [in] HRPWMx               HRPWM unit
 *  @arg CM_HRPWM_x
 * @retval None
 */
static void PWM_Config_Boost(CM_HRPWM_TypeDef *HRPWMx)
{
    stc_hrpwm_init_t stcHrpwmInit;
    stc_hrpwm_pwm_init_t stcPwmInit;

    (void)HRPWM_StructInit(&stcHrpwmInit);
    #if 0
    /* HRPWM general count function configure */
    stcHrpwmInit.u32CountMode = HRPWM_MD_TRIANGLE;
    stcHrpwmInit.u32CountReload = HRPWM_CNT_RELOAD_ON;
    stcHrpwmInit.u32PeriodValue = HRPWM_PERIOD_VALUE;
    (void)HRPWM_Init(HRPWMx, &stcHrpwmInit);

    (void)HRPWM_PWM_StructInit(&stcPwmInit);
    /* Configure PWM output */
    stcPwmInit.u32CompareValue = HRPWM_CMP_VALUE;
    stcPwmInit.u32StartPolarity = A_start_level;
    stcPwmInit.u32UpMatchAPolarity = HRPWM_PWM_UP_MATCH_A_INVT;
    stcPwmInit.u32PeakPolarity = HRPWM_PWM_PEAK_HOLD;
    stcPwmInit.u32DownMatchAPolarity = HRPWM_PWM_DOWN_MATCH_A_INVT;
    stcPwmInit.u32ValleyPolarity = HRPWM_PWM_VALLEY_HOLD;
    #else
    /* HRPWM general count function configure */
    stcHrpwmInit.u32CountMode = HRPWM_MD_SAWTOOTH;
    stcHrpwmInit.u32CountReload = HRPWM_CNT_RELOAD_ON;
    stcHrpwmInit.u32PeriodValue = HRPWM_PERIOD_VALUE;
    (void)HRPWM_Init(HRPWMx, &stcHrpwmInit);

    (void)HRPWM_PWM_StructInit(&stcPwmInit);
    /* Configure PWM output */
    stcPwmInit.u32CompareValue = BUCK_HRPWM_CMP_MINI_DUTY_VALUE;
    stcPwmInit.u32StartPolarity = HRPWM_PWM_START_HIGH;
    stcPwmInit.u32UpMatchAPolarity = HRPWM_PWM_UP_MATCH_A_LOW;
    stcPwmInit.u32PeakPolarity = HRPWM_PWM_PEAK_HOLD;
    stcPwmInit.u32DownMatchAPolarity = HRPWM_PWM_DOWN_MATCH_A_HOLD;
    stcPwmInit.u32ValleyPolarity = HRPWM_PWM_VALLEY_HOLD;
    #endif
    
    stcPwmInit.u32UpMatchBPolarity = HRPWM_PWM_UP_MATCH_B_HIGH;
    stcPwmInit.u32DownMatchBPolarity = HRPWM_PWM_DOWN_MATCH_B_HOLD;
    stcPwmInit.u32UpMatchEPolarity = HRPWM_PWM_UP_MATCH_E_HOLD;
    stcPwmInit.u32DownMatchEPolarity = HRPWM_PWM_DOWN_MATCH_E_HOLD;
    stcPwmInit.u32UpMatchFPolarity = HRPWM_PWM_UP_MATCH_F_HOLD;
    stcPwmInit.u32DownMatchFPolarity = HRPWM_PWM_DOWN_MATCH_F_HOLD;
    stcPwmInit.u32UpMatchSpecialAPolarity = HRPWM_PWM_UP_MATCH_SPECIAL_A_HOLD;
    stcPwmInit.u32DownMatchSpecialAPolarity = HRPWM_PWM_DOWN_MATCH_SPECIAL_A_HOLD;
    stcPwmInit.u32UpMatchSpecialBPolarity = HRPWM_PWM_UP_MATCH_SPECIAL_B_HOLD;
    stcPwmInit.u32DownMatchSpecialBPolarity = HRPWM_PWM_DOWN_MATCH_SPECIAL_B_HOLD;
    (void)HRPWM_PWM_ChAInit(HRPWMx, &stcPwmInit);
    stcPwmInit.u32StartPolarity = HRPWM_PWM_START_LOW;
    (void)HRPWM_PWM_ChBInit(HRPWMx, &stcPwmInit);
    /* PWM output enable */
    HRPWM_PWM_ChAOutputEnable(HRPWMx);
    HRPWM_PWM_ChBOutputEnable(HRPWMx);
}

/**
 * @brief  Configure HRPWM buffer function
 * @param  [in] HRPWMx               HRPWM unit
 *  @arg CM_HRPWM_x
 * @retval None
 */
static void HRPWM_Buffer_Config(CM_HRPWM_TypeDef *HRPWMx)
{
    stc_hrpwm_buf_config_t stcBufConfig;

    (void)HRPWM_BufStructInit(&stcBufConfig);
    /* General compare buffer function configure */
    stcBufConfig.u32BufTransCond = HRPWM_BUF_TRANS_VALLEY;
    (void)HRPWM_GeneralAEBufConfig(HRPWMx, &stcBufConfig);
    (void)HRPWM_GeneralBFBufConfig(HRPWMx, &stcBufConfig);
    HRPWM_PeriodBufConfig(HRPWMx, &stcBufConfig);
    HRPWM_PeriodBufEnable(HRPWMx);

    HRPWM_GeneralAEBufEnable(HRPWMx);
    HRPWM_GeneralBFBufEnable(HRPWMx);
    // HRPWM_GeneralBFBufEnable(HRPWMx);
    /* Set General Compare Register buffer Value */
}


RAM_FUNC void hrpwm_set_cmp_values(CM_HRPWM_TypeDef *HRPWMx,HRPWM_CmpDat_T cmp_dat){
    // HRPWM_SetCompareAValue_Buf(HRPWMx,cmp_dat.cmp_a_value);
    DDL_ASSERT(IS_HRPWM_UNIT(HRPWMx));
    DDL_ASSERT(IS_HRPWM_DATA_REG_RANGE1(cmp_dat.cmp_a_value));
    WRITE_REG32(HRPWMx->HRGCMCR, cmp_dat.cmp_a_value);
    // HRPWM_SetCompareBValue_Buf(HRPWMx,cmp_dat.cmp_b_value);
    DDL_ASSERT(IS_HRPWM_UNIT(HRPWMx));
    DDL_ASSERT(IS_HRPWM_DATA_REG_RANGE1(cmp_dat.cmp_b_value));
    WRITE_REG32(HRPWMx->HRGCMDR, cmp_dat.cmp_b_value);
    // HRPWM_SetCompareEValue_Buf(HRPWMx,cmp_dat.cmp_e_value);
    DDL_ASSERT(IS_HRPWM_UNIT(HRPWMx));
    DDL_ASSERT(IS_HRPWM_DATA_REG_RANGE1(cmp_dat.cmp_e_value));
    WRITE_REG32(HRPWMx->HRGCMGR, cmp_dat.cmp_e_value);
    // HRPWM_SetCompareFValue_Buf(HRPWMx,cmp_dat.cmp_f_value);
    DDL_ASSERT(IS_HRPWM_UNIT(HRPWMx));
    DDL_ASSERT(IS_HRPWM_DATA_REG_RANGE1(cmp_dat.cmp_f_value));
    WRITE_REG32(HRPWMx->HRGCMHR, cmp_dat.cmp_f_value);
}

/**************************************************************************
 * @brief 在锯齿波模式下，比较值不得设置为大于周期值加减1个PCLK0周期的值（不包括等于周期值），
 * 否则将会出现不可预期的波形，限制范围如图 19-10所示。如果要设置比较值大于周期值，
 * 必须将比较值设置为周期值+1个PCLK0，此时才能保证比较匹配不发生。（比较值大于周期值时，不产生匹配）
 * @param follow_cmp_value 
 * @param period 
 * @param duty 
 * @return HRPWM_CmpDat_T 
 *************************************************************************/
RAM_FUNC HRPWM_CmpDat_T hrpwm_buck_get_cmp_value(uint32_t follow_cmp_value, uint32_t period, float duty) {
    HRPWM_CmpDat_T cmp_dat = {0xc1, 0xc1, 0xc1, 0xc1};

    if (follow_cmp_value) {
        cmp_dat.cmp_a_value = follow_cmp_value + HRPWM_GET_DEADTIME(50u);
        cmp_dat.cmp_b_value = cmp_dat.cmp_a_value + (1.0f - duty) * period;
    } else {
        cmp_dat.cmp_a_value = (1.0f - duty) * period;
        cmp_dat.cmp_b_value = period - 65;
    }
    
    if (cmp_dat.cmp_b_value > (period - 65)) cmp_dat.cmp_b_value = period - 65;

    cmp_dat.cmp_e_value = cmp_dat.cmp_a_value+(cmp_dat.cmp_b_value-cmp_dat.cmp_a_value)/2;

    return cmp_dat;
}

RAM_FUNC HRPWM_CmpDat_T hrpwm_boost_get_cmp_value(uint32_t follow_cmp_value, uint32_t period, float duty) {
    HRPWM_CmpDat_T cmp_dat = {0xc1, 0xc1, 0xc1, 0xc1};

    if (follow_cmp_value) {
        cmp_dat.cmp_a_value = follow_cmp_value + HRPWM_GET_DEADTIME(50u);
        cmp_dat.cmp_b_value = cmp_dat.cmp_a_value + (duty)*period;
    } else {
        cmp_dat.cmp_a_value = HRPWM_GET_DEADTIME(50u);
        cmp_dat.cmp_b_value = cmp_dat.cmp_a_value + (duty)*period;
    }

    if (cmp_dat.cmp_b_value > (period - 65)) cmp_dat.cmp_b_value = period - 65;

    return cmp_dat;
}

RAM_FUNC uint32_t hrpwm_set_pwm_out_freq(CM_HRPWM_TypeDef *HRPWMx, uint32_t frea_kHz) {
    uint32_t period_value = GET_HRPWM_PERIOD_VALUE(frea_kHz);
    // HRPWM_SetPeriodValue_Buf(HRPWMx, period_value);
    DDL_ASSERT(IS_HRPWM_UNIT(HRPWMx));
    DDL_ASSERT(IS_HRPWM_DATA_REG_RANGE1(period_value));
    WRITE_REG32(HRPWMx->HRPERBR, period_value);

    return period_value;
}

/**
 * @brief  Main function
 * @param  None
 * @retval int32_t return value, if needed
 */
int32_t usr_buck_hrpwm_init(void) {
    /* Unlock peripherals or registers */
    // LL_PERIPH_WE(EXAMPLE_PERIPH_WE);
    /* Configure BSP */
    // stc_hrpwm_pwm_output_init_t pstcPwmOutputInit;

    FCG_Fcg2PeriphClockCmd(HRPWM_BUCK_PWM_FCG, ENABLE);
    /* PWM output port configure */
    GPIO_HrpwmPinCmd(HRPWM_BUCK_PORT, ENABLE);

    HRPWM_CommonDeInit();
    HRPWM_DeInit(HRPWM_BUCK_PWM_UNIT);

    /* Calibrate */
    if (LL_OK != HRPWM_CALIB_ProcessSingle()) {
        DDL_Printf("HRPWM Calibrate failed!!\n");
        return -1;
    }
    /* HRPWM function enable */
    HRPWM_Enable(HRPWM_BUCK_PWM_UNIT);

    PWM_Config_Buck(HRPWM_BUCK_PWM_UNIT);
    HRPWM_Buffer_Config(HRPWM_BUCK_PWM_UNIT);

    DeadTime_Config(HRPWM_BUCK_PWM_UNIT);
    HRPWM_DeadTimeEnable(HRPWM_BUCK_PWM_UNIT);

    HRPWM_IDLE_SetChAIdleLevel(HRPWM_BUCK_PWM_UNIT,HRPWM_IDLE_CHA_LVL_LOW);
    HRPWM_IDLE_SetChBIdleLevel(HRPWM_BUCK_PWM_UNIT,HRPWM_IDLE_CHB_LVL_HIGH);

    return 0;
}


/**
 * @brief  Main function
 * @param  None
 * @retval int32_t return value, if needed
 */
int32_t usr_boost_hrpwm_init(void) {
    /* Unlock peripherals or registers */
    // LL_PERIPH_WE(EXAMPLE_PERIPH_WE);
    /* Configure BSP */
    // stc_hrpwm_pwm_output_init_t pstcPwmOutputInit;

    FCG_Fcg2PeriphClockCmd(HRPWM_BST_PWM_FCG, ENABLE);
    /* PWM output port configure */
    GPIO_HrpwmPinCmd(HRPWM_BST_PORT, ENABLE);

    HRPWM_CommonDeInit();
    HRPWM_DeInit(HRPWM_BST_PWM_UNIT);

    /* Calibrate */
    if (LL_OK != HRPWM_CALIB_ProcessSingle()) {
        DDL_Printf("HRPWM Calibrate failed!!\n");
        return -1;
    }
    /* HRPWM function enable */
    HRPWM_Enable(HRPWM_BST_PWM_UNIT);

    PWM_Config_Boost(HRPWM_BST_PWM_UNIT);
    HRPWM_Buffer_Config(HRPWM_BST_PWM_UNIT);

    DeadTime_Config(HRPWM_BST_PWM_UNIT);
    HRPWM_DeadTimeEnable(HRPWM_BST_PWM_UNIT);

    HRPWM_IDLE_SetChAIdleLevel(HRPWM_BST_PWM_UNIT,HRPWM_IDLE_CHA_LVL_LOW);
    HRPWM_IDLE_SetChBIdleLevel(HRPWM_BST_PWM_UNIT,HRPWM_IDLE_CHA_LVL_LOW);


    return 0;
}

void usr_hrpwm_start(void) {
    HRPWM_HWStartEnable(HRPWM_BUCK_PWM_UNIT);
    HRPWM_HWStartEnable(HRPWM_BST_PWM_UNIT );
}

void usr_hrpwm_stop_all(void){
    // HRPWM_Enable(HRPWM_BST_PWM_UNIT);
    HRPWM_HWStartDisable(HRPWM_BUCK_PWM_UNIT);
    HRPWM_HWStartDisable(HRPWM_BST_PWM_UNIT );
}
// /**
//  * @brief  Configure synchronous output
//  * @param  None
//  * @retval None
//  */
// static void SyncOutput_Config(void)
// {
//     stc_hrpwm_sync_output_config_t stcSyncConfig;
//     (void)HRPWM_SYNC_StructInit(&stcSyncConfig);
//     stcSyncConfig.u32Src = HRPWM_SYNC_SRC_U3_CNT_VALLEY;
//     stcSyncConfig.u32MatchBDir = HRPWM_SYNC_MATCH_B_DIR_DOWN;
//     stcSyncConfig.u32Pulse = HRPWM_SYNC_PULSE_NEGATIVE;
//     stcSyncConfig.u32PulseWidth = 100UL;
//     (void)HRPWM_SYNC_Config(&stcSyncConfig);

//     //   HRPWM_SWSyncStart(HRPWM_PWM_MUL_UNIT);
// }
